#include "atch_tcp.h"

void destroy_tcp_server_session(TcpServerSession **tss)
{
    if (*tss == NULL)
    {
        printf("destroy tcp server session is null\n");
        return;
    }
    free(*tss);
    *tss = NULL;
}
void destroy_tcp_server(SocketTcpServer **sts)
{
    if (*sts == NULL)
    {
        printf("destroy tcp server is null\n");
        return;
    }
    free(*sts);
    *sts = NULL;
}
void *tcp_server_session(void *parameter)
{
    TcpServerSession *tss = (TcpServerSession *)parameter;
    printf("session connect success !!!\n");
    if (tss->serverSessionConnectedAction != NULL)
    {
        tss->serverSessionConnectedAction(tss);
    }

    while (1)
    {
        int n = read(tss->clientfd, tss->buffer, sizeof(tss->buffer) - 1);
        if (n == 0)
        {
            break;
        }
        else if (n < 0)
        {
            if (errno == EINTR)
                continue;
            if (errno == EAGAIN || errno == EWOULDBLOCK)
                continue;
            perror("server read error");
            break;
        }
        else
        {
            tss->buffer[n] = '\0';
            if (tss->serverSessionReceiveAction != NULL)
                tss->serverSessionReceiveAction(tss);
        }
    }
    destroy_tcp_server_session(&tss);
    printf("session disconnect !!!\n");
    return NULL;
}
void *tcp_server_listen(void *parameter)
{
    SocketTcpServer *sts = (SocketTcpServer *)parameter;
    sts->serverfd = socket(AF_INET, SOCK_STREAM, 0);
    if (bind(sts->serverfd, (struct sockaddr *)&sts->serverAddr, sizeof(sts->serverAddr)) < 0)
    {
        perror("tcp server bind error");
        return NULL;
    }
    if (listen(sts->serverfd, 128) < 0)
    {
        perror("tcp server listen error");
        return NULL;
    }
    while (1)
    {
        TcpServerSession *tss = (TcpServerSession *)malloc(sizeof(TcpServerSession));
        tss->addrLen = sizeof(tss->clientAddr);
        int clientfd = accept(sts->serverfd, (struct sockaddr *)&tss->clientAddr, &tss->addrLen);
        if (clientfd < 0)
        {
            perror("tcp server accept error");
            destroy_tcp_server_session(&tss);
            break;
        }
        tss->clientfd = clientfd;
        tss->serverSessionReceiveAction = sts->serverSessionReceiveAction;
        tss->serverSessionConnectedAction = sts->serverSessionConnectedAction;
        pthread_create(&tss->t, NULL, tcp_server_session, tss);
    }
    return NULL;
}
SocketTcpServer *create_tcp_server(int port, void (*tssra)(TcpServerSession *), void (*tssca)(TcpServerSession *))
{
    SocketTcpServer *sts = (SocketTcpServer *)malloc(sizeof(SocketTcpServer));
    sts->port = htons(port);
    sts->serverSessionReceiveAction = tssra;
    sts->serverSessionConnectedAction = tssca;
    sts->serverAddr.sin_family = AF_INET;
    sts->serverAddr.sin_addr.s_addr = INADDR_ANY;
    sts->serverAddr.sin_port = sts->port;
    if (pthread_create(&sts->serverListenThread, NULL, tcp_server_listen, sts) < 0)
    {
        perror("create thread error");
        destroy_tcp_server(&sts);
        return NULL;
    }
    return sts;
}
ssize_t tcp_server_session_sendmsg(TcpServerSession *tss, char msg[])
{
    if (tss == NULL)
    {
        printf("tcp server session sendmsg tss is null \n");
        return -1;
    }
    ssize_t n = write(tss->clientfd, msg, strlen(msg));

    if (n < 0)
    {
        perror("tcp server session sendmsg error ");
    }
    return n;
}
void destroy_tcp_client_session(TcpClientSession **tcs)
{
    if (*tcs == NULL)
    {
        printf("destro tcp client session tcs is null\n");
        return;
    }
    free(*tcs);
    *tcs = NULL;
}
void tcp_client_session(TcpClientSession *tcs)
{
    if (tcs == NULL)
    {
        printf("tcp clietn session tcs is null\n");
        return;
    }
    while (1)
    {
        printf("wait for listen\n");
        int n = read(tcs->serverfd, tcs->buffer, sizeof(tcs->buffer) - 1);
        printf(".   n is.     %d \n", n);
        if (n == 0)
        {
            break;
        }
        else if (n < 0)
        {
            if (errno == EINTR)
                continue;
            if (errno == EAGAIN || errno == EWOULDBLOCK)
                continue;
            perror("client read error");
            break;
        }
        else
        {
            tcs->buffer[n] = '\0';
            if (tcs->clientSessionReceiveAction != NULL)
                tcs->clientSessionReceiveAction(tcs);
        }
    }
}
void *tcp_client_connect(void *parameter)
{
    TcpClientSession *tcs = (TcpClientSession *)parameter;

    if (tcs == NULL)
    {
        printf("tcp client connect tcs is null\n");
        return NULL;
    }
    tcs->serverfd = socket(AF_INET, SOCK_STREAM, 0);
    tcs->addrLen = sizeof(tcs->serverAddr);

    if (connect(tcs->serverfd, (struct sockaddr *)&tcs->serverAddr, tcs->addrLen) < 0)
    {
        perror("tcp clietn connnect error");
        destroy_tcp_client_session(&tcs);
        return NULL;
    }
    printf("tcp client connect success!");
    if (tcs->clientSessionConnectedAction != NULL)
        tcs->clientSessionConnectedAction(tcs);
    tcp_client_session(tcs);
    return NULL;
}
TcpClientSession *create_tcp_client_session(char ip[], int port, void (*tcsra)(TcpClientSession *), void (*tcsca)(TcpClientSession *))
{
    TcpClientSession *tcs = (TcpClientSession *)malloc(sizeof(TcpClientSession));
    tcs->ip = inet_addr(ip);
    tcs->port = htons(port);
    tcs->serverAddr.sin_addr.s_addr = tcs->ip;
    tcs->serverAddr.sin_family = AF_INET;
    tcs->serverAddr.sin_port = tcs->port;
    tcs->clientSessionConnectedAction = tcsca;
    tcs->clientSessionReceiveAction = tcsra;
    if (pthread_create(&tcs->clientThread, NULL, tcp_client_connect, tcs) < 0)
    {
        perror("create tcp client session error");
        destroy_tcp_client_session(&tcs);
        return NULL;
    }
    return tcs;
}
ssize_t tcp_client_session_sendmsg(TcpClientSession *tcs, char msg[], int msgLen)
{
    if (tcs == NULL)
    {
        printf("tcp client session sendmsg tcs is null\n");
        return -1;
    }
    ssize_t n = write(tcs->serverfd, msg, msgLen);
    if (n < 0)
    {
        perror("tcp client session sendmsg error");
    }
    return n;
}

void _tcp_server_callback(TcpServerSession *tss)
{
    printf("tcp server session callback success\n");
}

void _tcp_client_callback(TcpClientSession *tcs)
{
    printf("tcp client session callback success\n");
}
void _tcp_server_print(TcpServerSession *tss)
{
    printf("the server receive msg is -> %s\n", tss->buffer);
}
void _tcp_client_print(TcpClientSession *tcs)
{
    printf("the client receive msg is -> %s\n", tcs->buffer);
}
